#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h>
#include <signal.h>
#include "syscore.h"
#include "apis.h"
#include "common.h" 
#include "smstask.h"

#include <iconv.h>
#include <time.h>
#include <sys/time.h>
#include "transform.h"
#include "3gcmn.h"
#define  SMS_PRINTF               0
#define  SMS_RESEND_MAX_COUNT     3
#define  MSG_CONFIRM_TIMEOUT      60
#define  SELECT__S                0
#define  SELECT_US                300000

#define  DONGLE_HW_EM660          1
#define  HW_EM660_AT_PORT         2

#define  DONGLE_ZTE_MC2716        2
#define  ZTE_MC2716_AT_PORT       1

#define  DONGLE_HW_MC509          3
#define  HW_MC509_AT_PORT         2

#define  TEST_PUBLIC_IP_NUM       5
static const char *ipaddr[TEST_PUBLIC_IP_NUM] =
{
    "1.2.4.8", //cnnic
    "180.76.76.76", //baidu
    "8.8.8.8",
    "114.114.114.144",
    "202.120.2.101" 
};

static char AT[15] = { "AT\r"  };
static int32_t max_fd = 0;
static fd_set fds_collection;

bool smsIsOk = false;
bool tickIsOk = false;
bool checkWan = false; 
bool checkWanIsOk = false;

typedef unsigned char  byte;

typedef bool (*AT_RSP_PARSER)(const void* buf, int32_t* len, void *result);

typedef struct tag_AT_COMMAND
{
    char cmd[16];
    int32_t len;
    AT_RSP_PARSER parser;
} AT_CMD;

typedef struct tag_AT_RSP_HCMGR
{
    char callerID[16];
    int32_t year;
    int32_t month;
    int32_t day;
    int32_t hour;
    int32_t minute;
    int32_t second;
    int32_t lang;
    int32_t format;
    int32_t length;
    int32_t prt;
    int32_t prv;
    int32_t type;
    int32_t stat;
    char msg[AT_RSP_MAXLEN];
} AT_RSP_HCMGR;

typedef struct tag_AT_CMTI
{
    char mem[8];
    int32_t index;
} AT_RSP_CMTI;

typedef struct tag_AT_SYSINFO
{
    uint32_t srv_status;
    uint32_t srv_domain;
    uint32_t roam_status;
    uint32_t sys_mode;
    uint32_t sim_state;
} AT_SYSINFO;

/* SYSINFO definition */
typedef enum
{
    SYSINFO_STATUS_NO_SERVICE =  0,          //No Service;
    SYSINFO_STATUS_RESTRICTED_SERVICE = 1,   //restricted service (not supported by this product)
    SYSINFO_STATUS_VALID_SERVICE = 2,        //valid service   
    SYSINFO_STATUS_REGINAL_SERVICE = 3,      //restricted regional service (not supported by this product)
    SYSINFO_STATUS_SLEEP_MODE = 4,           //power-saving and deep sleep state 
    SYSINFO_STATUS_UNKNOWN  = 255            //unknown
}SysinfoStatus;

typedef enum
{
    SYSINFO_SRVDOMAIN_NO_SERVICE = 0,        //no service domain
    SYSINFO_SRVDOMAIN_CS_SERVICE = 1,        //only CS service
    SYSINFO_SRVDOMAIN_PS_SERVICE = 2,        //only PS service
    SYSINFO_SRVDOMAIN_BOTH_SERVICE = 3,      //CS + PS service
    SYSINFO_SRVDOMAIN_CELL_SEARCHING = 4,    //CS and PS are not registered, searching
    SYSINFO_SRVDOMAIN_UNKNOWN = 255          //This fixed value is always returned because the product does not support this parameter.
}SysinfoSrvDomain;

pthread_mutex_t mutex;
pthread_mutex_t checkWanMutex;
void initMutex()
{
    pthread_mutex_init(&mutex, NULL);
    pthread_mutex_init(&checkWanMutex, NULL);
}

void setTickTrue()
{
    pthread_mutex_lock(&mutex);
    tickIsOk = true;
    pthread_mutex_unlock(&mutex);
}

bool CheckTick()
{
    bool alive = false;
    pthread_mutex_lock(&mutex);
    if ( tickIsOk )
    {
        tickIsOk = false;
        alive = true;
    }
    pthread_mutex_unlock(&mutex);
    return alive;
 
}
#ifdef MODULE_TEST

static bool testSms = false;
static bool testCheckWan = false;
void setTestCheckWan()
{
    testCheckWan = true;
}

void setTestSms()
{
    testSms = true;
}

#endif



void SetcheckWanTrue()
{
    pthread_mutex_lock(&checkWanMutex);
    checkWan = true;
    pthread_mutex_unlock(&checkWanMutex);
}

bool checkWanIsTrue()
{
    bool alive = false;
    pthread_mutex_lock(&checkWanMutex);
    if ( checkWan )
    {
        alive = true;
    }
    pthread_mutex_unlock(&checkWanMutex);
    return alive;
}

void SetCheckWanIsOk()
{
    pthread_mutex_lock(&checkWanMutex);
    checkWanIsOk = true;
    pthread_mutex_unlock(&checkWanMutex);
}

bool GetCheckWanThreadIsOk()
{
    bool alive = false;
    pthread_mutex_lock(&checkWanMutex);
    alive = checkWanIsOk;
    checkWanIsOk = false;
    pthread_mutex_unlock(&checkWanMutex);
    return alive;    
}

void debug_ascii(char *str, int32_t len)
{
    int32_t i;
    for(i=0; i<len; i++)
    {
        if((str[i]>=0x20 && str[i] <=0x7f) || str[i] == '\n' || str[i] == '\r')
        {
            printf("%c", str[i]);
        }
    }
}
void debug_dump_unicode(int num, char *str)
{
    if(num>0)
    {
        int inlen = 800;
        int outlen = 800;
        char *text;
        char *out;

        text = (char *)malloc(inlen+outlen);

        if(text == NULL)
        {
            DONGLE_LOG(LOG_ERR, "can not get menory!\n");
            return;
        }
        out  = text+inlen;
        memset(text, 0, inlen+outlen);

        text[0] = 0xfe;
        text[1] = 0xff;
        memcpy(text+2, str, num>inlen-2?798:num);
        
        Utf16ToUtf8(text, inlen, out, outlen);
        
        DONGLE_LOG(LOG_INFO,"%s\n", out);
        free(text);
    }
}

bool execCommand(const char* cmd, char* buf, int len)
{
    FILE *fpipe = (FILE*)popen(cmd, "r");

    if( NULL == fpipe )
    {
        DONGLE_LOG(LOG_ERR, "%s, popen error %d(%s) \n", __func__, errno, strerror(errno));
        bzero(buf, len);
        return false;
    }

    if( NULL == fgets(buf, len, fpipe))
    {
        if( 0 == errno )
        {
            bzero(buf, len);
            pclose(fpipe);
            return true;
        }
        DONGLE_LOG(LOG_ERR, "%s, fgets error %d(%s) \n", __func__, errno, strerror(errno));
        bzero(buf, len);
        pclose(fpipe);
        return false;
    }

    pclose(fpipe);

    char* nl = strchr(buf, '\n');
    if( nl )
    {
        *nl = '\0';
    }

    return true;
}

bool put_at_command(const void *at_cmd, int32_t cmd_len, void *at_rsp, int32_t *rsp_len, bool expect_ok);

bool parse_AT_HCMGL(const void *buf, int32_t *len, void *result);
bool parse_AT_HCMGR(const void *buf, int32_t *len, void *result);
bool parse_AT_CMIT_CDSI(const void *buf, int32_t *len, void *result);
bool parse_AT_DSDORMANT(const void *buf, int32_t *len, void *result);
bool parse_AT_HRSSILVL(const void *buf, int32_t *len, void *result);
bool parse_AT_CGMI(const void *buf, int32_t *len, void *result);
bool parse_AT_CGMM(const void *buf, int32_t *len, void *result);
bool parse_AT_CGMR(const void *buf, int32_t *len, void *result);
bool parse_AT_CIMI(const void *buf, int32_t *len, void *result);
bool parse_AT_HWVER(const void *buf, int32_t *len, void *result);
bool parse_AT_MEID(const void *buf, int32_t *len, void *result);
bool parse_AT_SYSINFO(const void *buf, int32_t *len, void *result);
bool parse_AT_HCMGSF(const void *buf, int32_t *len, void *result);
bool pase_AT_HCMGSS(const void *buf, int32_t *len, void *result);
bool parse_AT_HDRRSSI(const void *buf, int32_t *len, void *result);
bool parse_AT_SMMEMFULL(const void *buf, int32_t *len, void *result);

void parse_at_rsp(const void *buf, int32_t len);
void config_dongle();

byte at_ctrlz_a[1] = {0x1a};                             /* CTRL+Z */
byte at_ctrlz_u[2] = {0x00,0x1a};                        /* CTRL+Z */
byte at_cr_lf[2] = {0x0D,0x0A};                          /* <CR><LF> */
byte at_prefix[2] = {0x41,0x54};                         /* AT */
byte at_ok_rsp[6] = {0x0D,0x0A,0x4F,0x4B,0x0D,0x0A};     /* <CR><LF>OK<CR><LF> */
byte at_error_rsp[6] = {0x45,0x52,0x52,0x4F,0x52};       /* ERROR */
byte at_no_carrier[14] = {0x0D,0x0A,0x4E,0x4F,0x20,0x43,0x41,0x52,0x52,0x49,0x45,0x52,0x0D,0x0A};  /* <CR><LF>NO CARRIER<CR><LF> */
byte at_ok_2_rsp[] = {0x0D, 0x0A,0x0D,0x0A,0x4F,0x4B,0x0D,0x0A, 0};/* <CR><LF><CR><LF>OK<CR><LF> */


const char *modem_serial_dev[] = {"/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2", "/dev/ttyUSB3", "/dev/ttyUSB4"};

int32_t  dongle_model = 0;
char     dongle_model_string[64] = {0};
char     dongle_manufacturer[64] = {0};
char     dongle_hw_version[64] = {0};
char     dongle_sw_version[32] = {0};
char     dongle_uim_imsi[24] = {0};
char     dongle_meid[32] = {0};

int32_t  dongle_at_port = HW_MC509_AT_PORT;

int32_t  sms_serial_fd = -1;
int32_t  sms_recv_num = 0;
int32_t  sms_send_flag = 0;
int32_t  sms_accept_flag = 0;
int32_t  sms_resend_count = 0;
bool     sms_process = true;
bool     sms_list = 1;

struct timeval sms_timer;

AT_RSP_CMTI at_cmti = {{0}, 0};

AT_CMD at_cmd_list[] = {
    {"+CMTI", 5, parse_AT_CMIT_CDSI}, 
    {"+CDSI", 5, parse_AT_CMIT_CDSI},   /* SMS STATUS REPORT */
    {"^HCMGL", 6, parse_AT_HCMGL},
    {"^HCMGR", 6, parse_AT_HCMGR},
    {"^RSSILVL", 8, parse_AT_HRSSILVL},
    {"^HRSSILVL", 9, parse_AT_HRSSILVL},
    {"^DSDORMANT", 10, parse_AT_DSDORMANT},  /* no data activity, sleep */
    {"^HCMGSS", 7, pase_AT_HCMGSS},   /* send success */
    {"^HCMGSF", 7, parse_AT_HCMGSF},   /* send failure */
    {"^SIMST", 6, NULL},   /* SIM card status */
    {"^SMMEMFULL", 10, parse_AT_SMMEMFULL},   /* full */
    {"^MODE", 5, NULL},   /* sys mode report */
    {"^HDRRSSI", 8, parse_AT_HDRRSSI}, /* Report the HDR RSSI*/
    {"^CRSSI", 6, parse_AT_HDRRSSI} /* Report the RSSI*/
};

const char* srv_status[5] = {
    "no service",
    "limited service",
    "in service",
    "limited regional service",
    "power saving and deep sleep state"
};

const char send_successed[] = {(char)0x53, (char)0xd1, (char)0x90, (char)0x01, (char)0x62, (char)0x10, (char)0x52, (char)0x9f};

ssize_t readmsg(int32_t fd, char * buffer, int32_t length)
{
    ssize_t len = 0;
	
	do{
		len = read(fd, buffer, length);
	}while((len == -1) && (errno == EINTR));

	if(len < 0)
	{
	    DONGLE_LOG(LOG_ERR,  "read msg error \n");
	}

	return len;
}

ssize_t writemsg(int32_t fd, char * cmd, int32_t cmdLen)
{
    ssize_t len = 0;

	do
	{
		len = write(fd, cmd, cmdLen);
		if (len > 0)
		{
        	DONGLE_LOG(LOG_INFO,  "[MODEM]: %s \n", cmd);
			usleep(AT_COMMAND_INTERVAL);
		}
	}while((len == -1) && (errno == EINTR));

	if(len < 0)
	{
	    DONGLE_LOG(LOG_ERR,  "write command %s error \n", cmd);
	}

    return len;
}

void dongleRebootRequest()
{
    char msg_buf[MSG_BUFF_SIZE] = {0};
    MSGHEADER *msg_header = (MSGHEADER *)msg_buf;
    void* msg_payload = (void*)(msg_buf + sizeof(MSGHEADER));

    msg_header->srcID = MODULE_SMS;
    msg_header->dstID = MODULE_SYSTEM;
    msg_header->mType = get_mtype(msg_header->dstID);
    msg_header->msgType = MSG_TYPE_COMMAND;

    PCMDHEADER cmd = (PCMDHEADER)msg_payload;
    cmd->cmdType =  CMD_EVENT;
    cmd->cmdCode = CMD_CODE_SYS_REBOOT;
    cmd->cmdIndex = 0;
    cmd->cmdLength = 0;

    msg_header->msgLength = sizeof(MSGHEADER) + sizeof(CMDHEADER);
    uint8_t *ptr = (uint8_t *)msg_payload;
    ptr += sizeof(CMDHEADER);

    *(uint32_t*)ptr = PARA_TYPE_DELAY;
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = sizeof(uint32_t);
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = 6; //after 6 second
    ptr += sizeof(uint32_t);
    *(uint32_t*)ptr = 0; //padding

    cmd->cmdLength += sizeof(uint32_t) * 4;
    msg_header->msgLength += cmd->cmdLength;    

    if( ! send_qmsg((char *)msg_header, msg_header->msgLength) )
    {
        DONGLE_LOG(LOG_ERR, "can't report reboot msg, mtype=%d length=%d \n", 
                msg_header->msgType, msg_header->msgLength);

        //wait 5 second for logserver to log this message.
        sleep(5);
        //since reboot message sent failure, just reboot here
        system("reboot -f");            
    }
}

void raise_alarm(int32_t alarm_id, int32_t reason_code)
{
    SMS_ALARM alarm;
    alarm.header.msgId = MSG_ID_ALARM;
    alarm.id = alarm_id;
    alarm.reason = reason_code;
    alarm.action = 0;
    addMsgToFifoMsgQueue(&sms2MgrMsgQueue, (void**)&alarm, sizeof(SMS_ALARM));
}

int32_t open_serial_port(int32_t port_num)
{
    int32_t ret = 0;

    int32_t fd = open(modem_serial_dev[port_num], O_RDWR | O_NOCTTY | O_NDELAY);
    if( -1 == fd ) 
    {
        DONGLE_LOG(LOG_ERR, "can't open serial sort %s \n", modem_serial_dev[port_num]);

        return (-1);
    }

    if(DONGLE_HW_MC509 != dongle_model)
    {
        /* set blocking state */
        ret = fcntl(fd, F_SETFL , 0);
        if( ret < 0 )
        {
            DONGLE_LOG(LOG_ERR, "fcntl operation on fd(%d) failed\n", fd);
        }
    }

    /* test tty */
    if( isatty(STDIN_FILENO) == 0 )
    {
        DONGLE_LOG(LOG_ERR, "standard input is not a terminal device\n");
    }
    else
    {
        DONGLE_LOG(LOG_INFO, "standard input is a tty\n");
    }

    DONGLE_LOG(LOG_INFO, "open serial port %s done, get fd = %d \n", modem_serial_dev[port_num], fd);

    return fd;
}

int32_t set_serial_opt(int32_t fd, int32_t nSpeed, int32_t nBits, char nEvent, int32_t nStop)
{
    struct termios newtio, oldtio;
    if( tcgetattr(fd, &oldtio) != 0 )
    {                       
        DONGLE_LOG(LOG_ERR, "get fd(%d) attribute failed \n", fd);   
        return -1;
    }

    bzero(&newtio, sizeof (newtio));
    /* Active CLOCAL and CREAD */
    newtio.c_cflag |= CLOCAL | CREAD;

    switch( nSpeed )
    {
    case 2400:
        cfsetispeed(&newtio, B2400);
        cfsetospeed(&newtio, B2400);
        break;
    case 4800:
        cfsetispeed(&newtio, B4800);
        cfsetospeed(&newtio, B4800);
        break;
    case 9600:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    case 115200:
        cfsetispeed(&newtio, B115200);
        cfsetospeed(&newtio, B115200);
        break;
    case 460800:
        cfsetispeed(&newtio, B460800);
        cfsetospeed(&newtio, B460800);
        break;
    default:
        cfsetispeed(&newtio, B9600);
        cfsetospeed(&newtio, B9600);
        break;
    }

    /* Set data bit */
    newtio.c_cflag &= ~CSIZE;
    switch( nBits ) 
    {
    case 7:
        newtio.c_cflag |= CS7;
        break;
    case 8:
        newtio.c_cflag |= CS8;
        break;
    }

    switch( nEvent )
    {
    case 'O':
        newtio.c_cflag |= PARENB;
        newtio.c_cflag |= PARODD;
        newtio.c_iflag |= (INPCK | ISTRIP);
        break;
    case 'E':
        newtio.c_iflag |= (INPCK | ISTRIP);
        newtio.c_cflag |= PARENB;
        newtio.c_cflag &= ~PARODD;
        break;
    case 'N':
        newtio.c_cflag &= ~PARENB;
        break;
    }
  
    if( nStop == 1 )
    {
        newtio.c_cflag &= ~CSTOPB;
    }
    else if (nStop == 2)
    {
        newtio.c_cflag |= CSTOPB;
    }

    newtio.c_cc[VTIME] = 0;
    newtio.c_cc[VMIN] = 0;

    /* flush buffered data which are not sent yet */
    tcflush(fd, TCIFLUSH);

    /* Apply the new setting now */
    if( (tcsetattr(fd, TCSANOW, &newtio)) != 0 )
    { 
        DONGLE_LOG(LOG_ERR, "set fd(%d) attribute failed \n", fd);
        return -1;
    }

    DONGLE_LOG(LOG_INFO, "set serial port option done\n");
    return 0;
}

int32_t ReadATResponse(int32_t Fd, char * Buffer, int32_t BufferLen, int32_t * pDataLen)
{
    int32_t len;
    if ( Fd <= 0 )
    {
        DONGLE_LOG(LOG_ERR, "set fd(%d) attribute failed \n", Fd);
        return -1;
    }

    len = readmsg(Fd, Buffer + (*pDataLen), BufferLen - (*pDataLen));	
    if (len > 0)
    {
       (*pDataLen) += len;
    }

    return len;
}

int32_t SendATCommandgs(int32_t fd, char * command, int32_t commandLen, int32_t timeOut)
{
	char buffer[AT_BUFFER_SIZE];
	uint32_t i;
	int32_t bufferLen = 0;
	int32_t dataLen = 0;
	int32_t len = 0;
	int32_t ret = -1;
	uint32_t times = 0;
	int32_t maxFds = 0;
	struct timeval tv;
	fd_set readFds;

    if ( fd <= 0 )
    {
        DONGLE_LOG(LOG_ERR, "invalid fd = %d \n", fd);
        return -1;
    }

	//serial read timeout is 200ms
	times = timeOut * (1000000 / 200000); 
	bufferLen = sizeof(buffer);

	//clear up 
	len = readmsg(fd, buffer, bufferLen);
	if (len > 0)
	{
		DONGLE_LOG(LOG_INFO, "at rcv buff none\n");
		usleep(AT_COMMAND_INTERVAL);
	}

	memset(buffer, 0, sizeof(buffer));
	maxFds = fd + 1;

	//send at command
	DONGLE_LOG(LOG_INFO, "send at command %s\n", command);
	writemsg(fd, command, commandLen);

	// 在规定时间内读出内容
	for (i = 0; i < times; i++)
	{
		FD_ZERO(&readFds);
		FD_SET(fd, &readFds);
		tv.tv_sec = 0; 
		tv.tv_usec = 200000;	

		ret = select(maxFds, &readFds, NULL, NULL, &tv);
		if (ret == 0)
		{
			continue;
		}
        else if (ret < 0)
        {
            DONGLE_LOG(LOG_ERR, "fd select failure. \n");
            return -1;
        }
		
		if (FD_ISSET(fd, &readFds))
		{
			ReadATResponse(fd, buffer, bufferLen, &dataLen);
			if (strstr(buffer, CRLF_ERROR_CRLF))
			{
				DONGLE_LOG(LOG_ERR, "[MODEM ERROR]: [%s] \n", buffer);
				return -1;
			}
			else
			if (strstr(buffer, CRLF_OK_CRLF))
			{
				DONGLE_LOG(LOG_INFO, "[MODEM OK]: [%s] \n", buffer);
				return 0;
			}
			else
			if (strstr(buffer, ">"))
			{
				DONGLE_LOG(LOG_INFO, "[MODEM OK]: [%s] \n", buffer);
				return 0;
			}
			else
			{
				DONGLE_LOG(LOG_ERR, "[MODEM] [%s] \n", buffer);
				continue;
			}
		}
	}

	DONGLE_LOG(LOG_ERR, "[MODEM] <%s> response time out %d <%d>! \n", command, timeOut, times);
	return -1;
}


int32_t SendATCommand(int32_t fd, char * command, int32_t commandLen, int32_t timeOut)
{
	char buffer[AT_BUFFER_SIZE];
	uint32_t i;
	int32_t bufferLen = 0;
	int32_t dataLen = 0;
	int32_t len = 0;
	int32_t ret = -1;
	uint32_t times = 0;
	int32_t maxFds = 0;
	struct timeval tv;
	fd_set readFds;

    if ( fd <= 0 )
    {
	     DONGLE_LOG(LOG_WARNING, "SendATCommand failed fd %d\n", fd);
         return -1;
    }

	//serial read timeout is 200ms
	times = timeOut * (1000000 / 200000); 

	bufferLen = sizeof(buffer);

	//clear msg buffer
	len = readmsg(fd, buffer, bufferLen);
	if (len > 0)
	{
		DONGLE_LOG(LOG_INFO, "at rcv buff none\n");
		usleep(AT_COMMAND_INTERVAL);
	}
	memset(buffer, 0, sizeof(buffer));
	maxFds = fd + 1;

	DONGLE_LOG(LOG_INFO, "send at command %s\n", command);
	//send at command
	writemsg(fd, command, commandLen);

	//read the response in the limited time
	for (i = 0; i < times; i++)
	{
		FD_ZERO(&readFds);
		FD_SET(fd, &readFds);
		tv.tv_sec = 0; 
		tv.tv_usec = 200000;	

		ret = select(maxFds, &readFds, NULL, NULL, &tv);
		if (ret == -1)
		{
			continue;
		}
		
		if (FD_ISSET(fd, &readFds))
		{
			ReadATResponse(fd, buffer, bufferLen, &dataLen);
			if (strstr(buffer, CRLF_ERROR_CRLF))
			{
				DONGLE_LOG(LOG_ERR, "[MODEM ERROR]: [%s] \n", buffer);
				return -1;
			}
			else if (strstr(buffer, CRLF_OK_CRLF))
			{
				DONGLE_LOG(LOG_INFO, "[MODEM OK]: [%s] \n", buffer);
				return 0;
			}
			else
			{
				DONGLE_LOG(LOG_ERR,  "[MODEM] [%s] \n", buffer);
				continue;
			}
		}
	}

	DONGLE_LOG(LOG_ERR, "[MODEM] <%s> response time out %d <%d>! \n", command, timeOut, times);
	return -1;
}

int32_t SendATCommandX(int32_t fd, char * command, int32_t commandLen, char * buffer, int32_t bufferLen, const char * flags[],
	                   int32_t flagCount, int32_t * dataLen, int32_t timeOut)
{
	uint32_t i = 0;
	int32_t j = 0;
	int32_t len = 0;
	int32_t ret = -1;
	uint32_t times = 0;
	int32_t maxFds = 0;
	struct timeval tv;
	fd_set readFds;

    if ( fd <= 0 )
    {
	     DONGLE_LOG(LOG_WARNING, "SendATCommandX failed fd %d\n", fd);
         return -1;
    }

	*dataLen = 0;

    //serial read timeout is 200ms
	times = timeOut * (1000000 / 200000);

	//clear read buffer
	len = readmsg(fd, buffer, bufferLen);
	if (len > 0)
	{
       	DONGLE_LOG(LOG_INFO,  "[MODEM]: %s \n", buffer);
		usleep(AT_COMMAND_INTERVAL);
	}
		
	memset(buffer, 0, bufferLen);
	
	DONGLE_LOG(LOG_INFO, "send at command %s\n", command);
	maxFds = fd + 1;

	//send AT command
	writemsg(fd, command, commandLen);
	
	//read the response in the limited time
	for (i = 0; i < times; i++)
	{
		FD_ZERO(&readFds);
		FD_SET(fd, &readFds);
		tv.tv_sec = 0; 
		tv.tv_usec = 200000;	

		ret = select(maxFds, &readFds, NULL, NULL, &tv);
		if (ret == -1)
		{
			continue;
		}
		
		if (FD_ISSET(fd, &readFds))
		{
			ReadATResponse( fd, buffer, bufferLen, dataLen);

			DONGLE_LOG(LOG_INFO, "[MODEM]: %s datalen %d \n", buffer, *dataLen);
			for (j = 0; j < flagCount; j++)
			{
				//find the flag, and break the for 
				if (strstr(buffer, flags[j]))
				{
					ReadATResponse(fd, buffer, bufferLen, dataLen);
					DONGLE_LOG(LOG_INFO,  "[MODEM]: %s \n", buffer);
					return 0;
				}
			}
		}
	}

	DONGLE_LOG(LOG_ERR, "[MODEM] <%s>response time out %d<%d>! \n", command, timeOut, times);
	return -1;
}

bool renew_serial_fd(int32_t port_num)
{
    if( 0 == sms_serial_fd )
    {
        DONGLE_LOG(LOG_INFO, "serial fd is zero \n");
        goto reboot;
    }

    close(sms_serial_fd);
    sms_serial_fd = -1;

    sleep(3);

    sms_serial_fd = open_serial_port(port_num);
    if( sms_serial_fd < 0 )
    {
        DONGLE_LOG(LOG_ERR, "open serial port %d failed \n", port_num);
        goto reboot;
    }

    if( set_serial_opt(sms_serial_fd, 115200, 8, 'N' , 1) < 0 )
    {
        DONGLE_LOG(LOG_ERR, "set serial option failed\n");

        goto reboot;
    }

    DONGLE_LOG(LOG_INFO, "renew serial fd ok \n");

    max_fd = sms_serial_fd;
    FD_ZERO(&fds_collection);
    if( FD_ISSET(sms_serial_fd, &fds_collection) == 0 )
    {
        DONGLE_LOG(LOG_INFO, "add %d to fd_set\n", sms_serial_fd);
        FD_SET(sms_serial_fd, &fds_collection);
    }
    else
    {
        DONGLE_LOG(LOG_ERR, "add %d to fd_set failure .\n", sms_serial_fd);
        goto reboot;
    }

    return true;
reboot:
    dongleRebootRequest();
    return false;
}

bool reset_dongle(int32_t port_num)
{
    char rsp_buf[AT_RSP_MAXLEN] = {0};
    char cmd[1024] = {0};
    const char *dongle_sh = "/usr/bin/dongle.sh";

    int32_t try_closefd = 60;
    int32_t try_set_at = 240;
    char RESET[15] = { "AT^RESET=10\r" };
    int32_t try_open_serial = 60;

    DONGLE_LOG(LOG_NOTICE, "trying to reset dongle ...\n");

    if( sms_serial_fd < 0 )
    {
        sms_serial_fd = open_serial_port(port_num);
        if( sms_serial_fd < 0 )
        {
            DONGLE_LOG(LOG_ERR, "open serial port failed\n");
            goto reboot;
        }

        if( set_serial_opt(sms_serial_fd, 115200, 8, 'N' , 1) < 0 )
        {
            DONGLE_LOG(LOG_ERR, "set serial option failed\n");
            goto reboot;
        }
    }

    /* stop 3g wan connection */
    DONGLE_LOG(LOG_ERR, "disconnect 3g wan ...\n");

    sprintf(cmd, "%s -d %s \n", dongle_sh, "wan");
    if( ! execCommand(cmd, rsp_buf, AT_RSP_MAXLEN) )
    {
        DONGLE_LOG(LOG_ERR, "exec shell command failed\n");
        goto reboot;
    }

    /* wait for 3g connection down */
    sleep(10);

    /* Reset 3G dongle */
    SendATCommand(sms_serial_fd, RESET, strlen(RESET), CONFIG_COMMAND_TIMEOUT);

    DONGLE_LOG(LOG_INFO, "write AT RESET command done \n");

    while( try_closefd > 0 )
    {
       if ( close(sms_serial_fd) == 0 )
       {
           break;
       }

       try_closefd--;
       sleep(1);
    }
    
    sms_serial_fd = -1;
    sleep(20);

    while( try_open_serial > 0 )
    {
        sms_serial_fd = open_serial_port(port_num);
        if( sms_serial_fd < 0 )
        {
            try_open_serial--;
            sleep(1);
        }
        else
        {
            break;
        }
    }

    if (try_open_serial <= 0)
    {
        goto reboot;
    }

    if( sms_serial_fd < 0 )
    {
        DONGLE_LOG(LOG_ERR, "open serial port failed\n");
        goto reboot;
    }

    if( set_serial_opt(sms_serial_fd, 115200, 8, 'N' , 1) < 0 )
    {
        DONGLE_LOG(LOG_ERR, "set serial option failed\n");
        goto reboot;
    }

    while( try_set_at > 0 )
    {
        DONGLE_LOG(LOG_ERR, "check RESET done ... \n");
        if( SendATCommand(sms_serial_fd, AT, strlen(AT), CONFIG_COMMAND_TIMEOUT) == 0 )
        {
            DONGLE_LOG(LOG_ERR, "reset 3G dongle done\n");

            /* start 3g wan connection */
            sprintf(cmd, "%s -u %s \n", dongle_sh, "wan");
            if( ! execCommand(cmd, rsp_buf, AT_RSP_MAXLEN) )
            {
                DONGLE_LOG(LOG_ERR, "exec shell command failed\n");
                goto reboot;
            }

            break;
        }

        try_set_at--;
        sleep(1);
    }

    if ( try_set_at <= 0 )
    {
        DONGLE_LOG(LOG_ERR, "3g dongle reset time out.\n");
        goto reboot;
    }

    //after reset dongle, then try to config dongle at this place;
    sleep(5);
    config_dongle();

    DONGLE_LOG(LOG_NOTICE, "reset dongle success.\n");
    return true;

reboot:
    dongleRebootRequest();   
    return false;
}

void config_dongle()
{
    max_fd = sms_serial_fd;
    FD_ZERO(&fds_collection);
    if( FD_ISSET(sms_serial_fd, &fds_collection) == 0 )
    {
        DONGLE_LOG(LOG_INFO, "add %d to fd_set\n", sms_serial_fd);
        FD_SET(sms_serial_fd, &fds_collection);
    }
    else
    {
        DONGLE_LOG(LOG_ERR, "add %d to fd_set failed.\n", sms_serial_fd);
    }

    /* ATE0 disable echo AT commands, ATE1 enable echo AT commands */
    char ATE0[15] = { "ATE0\r" };  
    SendATCommand(sms_serial_fd, ATE0, strlen(ATE0), CONFIG_COMMAND_TIMEOUT);
    
    /* Set the format of result code and information response */
    char ATV1[15] = { "ATV1\r" };
    SendATCommand(sms_serial_fd, ATV1, strlen(ATV1), CONFIG_COMMAND_TIMEOUT);    

    /* Set the format of MT error report */
    char CMEE[15] = { "AT+CMEE=2\r" };
    SendATCommand(sms_serial_fd, CMEE, strlen(CMEE), CONFIG_COMMAND_TIMEOUT);     

    /* Set sms store to ME */
    char CPMS[25] = { "AT+CPMS=\"ME\",\"ME\",\"ME\"\r" };
    SendATCommand(sms_serial_fd, CPMS, strlen(CPMS), CONFIG_COMMAND_TIMEOUT);     

    /* Set text mode, pdu is not supported by cdma */
    char CMGF[25] = { "AT+CMGF=1\r" };
    SendATCommand(sms_serial_fd, CMGF, strlen(CMGF), CONFIG_COMMAND_TIMEOUT);     

    /* Set new sms notice method */
    char CNMI[25] = { "AT+CNMI=1,1,0,2,0\r" };
    SendATCommand(sms_serial_fd, CNMI, strlen(CNMI), CONFIG_COMMAND_TIMEOUT);      

    
    /* clean all short message */
    char CMGD[15] = { "AT+CMGD=1,4\r" };
    SendATCommand(sms_serial_fd, CMGD, strlen(CMGD), 10 * CONFIG_COMMAND_TIMEOUT);     
    sleep(2);

    /* re-set ATE0 */
    char ATE01[15] = { "ATE0\r" };  
    SendATCommand(sms_serial_fd, ATE01, strlen(ATE01), CONFIG_COMMAND_TIMEOUT);
}

#if 0
int32_t change_number(char * pSrc) 
{
    int32_t i;
    char c;
    char F[] = "F";
    int32_t length = strlen(pSrc);

    if( length & 1 )            
    {
        strcat(pSrc, F) ;   // \B2\B9'F'
        printf("%s\n", pSrc) ;
    }

    for( i = 0; i < length; i += 2 ) 
    {
        c = pSrc ;
        pSrc = pSrc ;
        pSrc = c ;
    }
   
    printf("changed number is: %s\n", pSrc);
    return 0 ;
}

int32_t send_pdu_sms()
{
    int32_t fd;
    int32_t nwrite, readnum, i;
    char buff[]="AT\r"; // AT command
    char readstr[AT_RSP_MAXLEN];
    char send[200];
    char send2[100];
    char centeraddr[] = "8613800100500";     // SMS center number
    char usraddr[] = "861510104175x";    // dest number

    char head[] = "0891";

    char phone[] = "1100";
    char pho[] = "0D91" ;
    char phoafter[] = "0008000" ;
    char firemsg[] = "0A5bb691cc7740706bff01";  // message 1
    char thiefmsg[] = "0A5c0f50778fdb5c4bff01";  // message 2
    
    if( (fd = open_serial_port(fd, 2)) < 0 )
    {
        printf("Open serial port failed");
        return -1;
    }

    if( set_serial_opt(fd, 115200, 8, 'N' , 1) < 0 )
    {
        printf("Set serial option failed\n");
        return -1;
    }

    //send=head+phone+msg+\x1a
    change_number(centeraddr);
    printf("after change, the centeraddr is %s\n", centeraddr);

    strcpy(send, head);     //head=0891
    printf("%s\n", send);
    strcat(send, centeraddr);
    printf("the send is %s\n %d\n", send, strlen(send));
    change_number(usraddr);
    printf("after change, the usraddr is %s\n",usraddr);

    strcat(phone, pho);
    printf("%s\n", phone);
    strcat(phone, usraddr);
    printf("%s\n", phone);

    strcat(phone, phoafter);
    printf("the phone is %20s\n", phone);
    strcat(send, phone);
    printf("%s\n", send);

    strcat(send, "\x1a");

    printf("%20s\n%d\n",send,strlen(send));

    write(fd, "AT\r", 3);
    sleep(2);
    readnum = read(fd, readstr, AT_RSP_MAXLEN);
    if( strstr(readstr, "OK") == NULL )
    {
        printf("the com port is fault!!\n");
    }
    else
    {
        printf("readnum=%d, %s\n", readnum, readstr);
    }

    write(fd, "AT+CMGF=0\r", 10);
    sleep(2);
    readnum = read(fd, readstr, AT_RSP_MAXLEN);
    // if(strstr(readstr,"OK") == NULL)
    // printf("the select PDU is faule!!\n");
    if( readnum != 0 )
    {
        printf("readnum=%d, %s\n", readnum, readstr);
    }

    write(fd, "AT+CMGS=27\r", 11);
    sleep(1);
    readnum = read(fd, readstr, AT_RSP_MAXLEN);
    if( readnum != 0 )
    {
        printf("%s %d PDU CMD\n", readstr, readnum);
    }
    
    while( !strstr(readstr, "\r\n>") )
    {
        read(fd, readstr, AT_RSP_MAXLEN);
    }

    write(fd, send, strlen(send));
    read(fd, readstr, AT_RSP_MAXLEN);
    printf("%s\n", readstr);
    sleep(3);
    close(fd);
    return 0;
}
#endif

/* byte_cmp: buf_len must >= key_len */
bool byte_cmp(const byte *buf, const byte *key, int32_t key_len)
{
    int32_t i = 0;
    for( ; i < key_len; ++i )
    {
        if( *(buf + i) != *(key + i) )
            return false;
    }
    return true;
}

bool find_str(const byte *buf, int32_t len, const byte *key, int32_t key_len, int32_t *pos)
{
    int32_t i = 0;

    for( ; i <= len - key_len; ++i )
    {
        if( byte_cmp(buf + i, key, key_len) )
        {
            *pos = i;
            return true;
        }
    }
    
    *pos = -1;   /* can't use pos value */
    return false;
}

bool find_ok_rsp(const void *buf, int32_t len)
{
    int32_t i = 0;
    byte *ptr = (byte *)buf;
    for( ; i + 5 < len; i++ )
    {
        if( (ptr[i] == 0xD) && (ptr[i+1] == 0xA) &&
            (ptr[i+2] == 'O' || ptr[i+2] == 'o') && 
            (ptr[i+3] == 'K' || ptr[i+3] == 'k') &&
            (ptr[i+4] == 0xD) && (ptr[i+5] == 0xA) )
            return true;
    }
    return false;
}

bool put_at_command(const void *at_cmd, int32_t cmd_len, void *at_rsp, int32_t *rsp_len, bool expect_ok)
{
    bool bret = true;
    int32_t  nret = 0, i = 0, pos = 0;

    write(sms_serial_fd, at_cmd, cmd_len);

    memset(at_rsp, 0, *rsp_len);
    if( expect_ok )
    {
        for( ; i < 30; ++i )
        {
            sleep(1);
            nret = readmsg(sms_serial_fd, (char *)at_rsp, *rsp_len);
            if( nret > 0 )
            {
#if (SMS_PRINTF == 1)                
               debug_dump_buffer(nret, at_rsp);
#endif
                if( !find_ok_rsp(at_rsp, nret) )
                {
                    pos = 0;
                    if( find_str((byte *)at_rsp, nret, at_error_rsp, 5, &pos) )
                    {
                        char cmd[128] = {0};
                        memcpy(cmd, at_cmd, cmd_len - 1);
                        /* ERROR response received */
 
                        DONGLE_LOG(LOG_ERR, "%s command failed, ERROR response received, %d ,%s\n", cmd, nret, (byte *)at_rsp);
                        /* @TODO add error parser */

                        reset_dongle(dongle_at_port);
                    }
                    else
                    {
                        char cmd[128] = {0};
                        memcpy(cmd, at_cmd, cmd_len - 1);
                        /* unknown response received */

                        DONGLE_LOG(LOG_ERR, "%s command failed, no OK response received, %d \n", cmd, nret);
                    }

                    bret = false;
                }

                *rsp_len = nret;
                break;  /* at response ok */
            }
        }
        
        if ( 30 <= i )
        {
            char cmd[128] = {0};
            memcpy(cmd, at_cmd, cmd_len - 1);
            DONGLE_LOG(LOG_ERR,  "%s command failed, no response received \n", cmd);

            renew_serial_fd(dongle_at_port);

            bret = false;
        }
    }
    else
    {
        sleep(2);
        nret = readmsg(sms_serial_fd, (char *)at_rsp, *rsp_len);
        if( nret > 0 )
        {
            *rsp_len = nret;
#if (SMS_PRINTF == 1)            
            debug_dump_buffer(nret, at_rsp);
#endif
        }
        else
            bret = false;
    }
    return bret;
}

int32_t send_sms(char* number, void* sms_buf, int32_t sms_len, bool unicode)
{

    int32_t  i = 0, rsp_len = 0;
    char at_cmd[64];
    char rsp_buf[AT_RSP_MAXLEN] = {0};

    memset(at_cmd, 0, sizeof(at_cmd));
    rsp_len = AT_RSP_MAXLEN;
    DONGLE_LOG(LOG_INFO,"sending msg...\n");
    if( SendATCommand(sms_serial_fd, AT, strlen(AT), CONFIG_COMMAND_TIMEOUT) != 0 )
    {
        DONGLE_LOG(LOG_WARNING, "AT command failure, please check if usb dongle is inserted.\n");
        raise_alarm(CMD_EVT_ALARM_SMS_AT_FAIL, PARA_TYPE_3G_ALARM_REASON_AT_ERR);

        reset_dongle(dongle_at_port);
        return -1;
    }

    rsp_len = AT_RSP_MAXLEN;
    /* AT^HSMSSS=<ack>,<prt>,<fmt>,<prv>*/
    if( unicode )
    {
        /* ack needed, unicode */
        char HSMSSS[25] = { "AT^HSMSSS=1,0,6,0\r" };
        SendATCommand(sms_serial_fd, HSMSSS, strlen(HSMSSS), CONFIG_COMMAND_TIMEOUT);
    }
    else
    {
        /* ack needed, ascii */
        char HSMSSS[25] = { "AT^HSMSSS=1,0,1,0\r" };
        SendATCommand(sms_serial_fd, HSMSSS, strlen(HSMSSS), CONFIG_COMMAND_TIMEOUT);
    }

    rsp_len = AT_RSP_MAXLEN;

    sprintf(at_cmd, "AT^HCMGS=\"%s\"\r", number);
    DONGLE_LOG(LOG_INFO,"cmd is %s   %d", at_cmd, strlen(at_cmd) );

    if( SendATCommandgs(sms_serial_fd, at_cmd, strlen(at_cmd), CONFIG_COMMAND_TIMEOUT * 10) < 0)
    {
        DONGLE_LOG(LOG_ERR, "read operation failed, can't write sms content\n");
    }
    else
    {
        writemsg(sms_serial_fd, (char *)sms_buf, sms_len);

        if( unicode )
        {
            writemsg(sms_serial_fd, (char *)at_ctrlz_u, 2);
        }
        else
        {
            writemsg(sms_serial_fd, (char *)at_ctrlz_a, 1);
        }

        /* For sending msg, need to wait 60s for responsing */
        for( i = 0; i < 60; ++i )
        {
            sleep(1);
            memset(rsp_buf, 0, AT_RSP_MAXLEN);
            rsp_len = readmsg(sms_serial_fd, (char *)rsp_buf, AT_RSP_MAXLEN);
            if( rsp_len > 0 )
            {
#if (SMS_PRINTF == 1)                
                debug_dump_buffer(rsp_len, rsp_buf);
                debug_ascii((char *)rsp_buf, rsp_len);
#endif
                if(strstr(rsp_buf, "HCMGSF:"))
                {
                    DONGLE_LOG(LOG_ERR, "send MSG fail!\n");
                    sms_send_flag = -1;
                    return 1;
                }

                if( DONGLE_HW_EM660 == dongle_model )
                {
                    if( ! find_ok_rsp(rsp_buf, rsp_len) )
                    {
                        DONGLE_LOG(LOG_ERR, "%s, send sms failed, no OK response received \n", __func__);
                    }

                    break;  /* at response ok */
                }
                else if( DONGLE_ZTE_MC2716 == dongle_model )
                {
                    /* no OK include */
                    break;
                }
                else if(DONGLE_HW_MC509 == dongle_model)
                {
                    /* wait for HCMGSS or HCMGSF */
                    if(strstr(rsp_buf, "HCMGSS:"))
                    {
                        DONGLE_LOG(LOG_NOTICE, "successfully send MSG!\n");
                        sms_send_flag = 0;
                        break;
                    }
                }
            }
        }

        if ( 60 <= i )
        {
            DONGLE_LOG(LOG_ERR,  "%s, send sms failed, no response received \n", __func__);

            return -1;
        }
    }

    return 0;
}

bool init_serial(int32_t port_num)
{
    void *result = NULL;
    char buff[8192] = {0};
    int32_t rspLen = 0;
    int32_t dataLen = 0;

    const char *FlagListOk[2] = { CRLF_OK_CRLF, CRLF_CMS_ERR_CRLF};

    if( sms_serial_fd > 0 )
    {
        DONGLE_LOG(LOG_ERR,  "serial port initialized\n");

        return false;
    }

    sms_serial_fd = open_serial_port(port_num);
    if( sms_serial_fd < 0 )
    {
        DONGLE_LOG(LOG_ERR,  "open serial port failed\n");

        return false;
    }

    if( set_serial_opt(sms_serial_fd, 115200, 8, 'N' , 1) < 0 )
    {
        DONGLE_LOG(LOG_ERR,  "set serial option failed\n");

        return false;
    }

    config_dongle();

    /* Query vandor */
    char CGMI[15] = { "AT+CGMI\r" };
    rspLen = SendATCommandX(sms_serial_fd, CGMI, strlen(CGMI), buff, 8192, FlagListOk,
	                        2,  &dataLen, CONFIG_COMMAND_TIMEOUT);
    if ( rspLen == 0 &&  dataLen >= 0)
    {
       parse_AT_CGMI(buff, &dataLen, result);
    }
    memset(buff, 0, 8192);
    dataLen = 0;

    /* Query product model */
    char CGMM[15] = { "AT+CGMM\r" } ;
    rspLen = SendATCommandX(sms_serial_fd, CGMM, strlen(CGMM), buff, 8192, FlagListOk,
	                        2,  &dataLen, CONFIG_COMMAND_TIMEOUT);
    if ( rspLen == 0 &&  dataLen >= 0)
    {
        parse_AT_CGMM(buff, &dataLen, result);
    }
    memset(buff, 0, 8192);
    dataLen = 0;    

    /* Query hw version */
    char HWVER[15] = { "AT^HWVER\r" } ;
    rspLen = SendATCommandX(sms_serial_fd, HWVER, strlen(HWVER), buff, 8192, FlagListOk,
	                        2,  &dataLen, CONFIG_COMMAND_TIMEOUT);
    if ( rspLen == 0 &&  dataLen >= 0)
    {
        parse_AT_HWVER(buff, &dataLen, result);
    }
    memset(buff, 0, 8192);
    dataLen = 0;           

    /* Query sw version */
    char CGMR[15] = { "AT+CGMR\r" } ;
    rspLen = SendATCommandX(sms_serial_fd, CGMR, strlen(CGMR), buff, 8192, FlagListOk,
	                        2,  &dataLen, CONFIG_COMMAND_TIMEOUT);
    if ( rspLen == 0 &&  dataLen >= 0)
    {
        parse_AT_CGMR(buff, &dataLen, result);
    }
    memset(buff, 0, 8192);
    dataLen = 0;           

    /* Query meid */
    char MEID[15] = { "AT^MEID\r" } ;
    rspLen = SendATCommandX(sms_serial_fd, MEID, strlen(MEID), buff, 8192, FlagListOk,
	                        2,  &dataLen, CONFIG_COMMAND_TIMEOUT);
    if ( rspLen == 0 &&  dataLen >= 0)
    {
        parse_AT_MEID(buff, &dataLen, result);
    }
    memset(buff, 0, 8192);
    dataLen = 0;     

    /* Query IMSI */
    char CIMI[15] = { "AT+CIMI\r" } ;
    rspLen = SendATCommandX(sms_serial_fd, CIMI, strlen(CIMI), buff, 8192, FlagListOk,
	                        2,  &dataLen, CONFIG_COMMAND_TIMEOUT);
    if ( rspLen == 0 &&  dataLen >= 0)
    {
        parse_AT_CIMI(buff, &dataLen, result);
    }
    memset(buff, 0, 8192);
    dataLen = 0;  

    /* Query sysinfo */
    char SYSINFO[15] = { "AT^SYSINFO\r" } ;
    rspLen = SendATCommandX(sms_serial_fd, SYSINFO, strlen(SYSINFO), buff, 8192, FlagListOk,
	                        2,  &dataLen, CONFIG_COMMAND_TIMEOUT);
    if ( rspLen == 0 &&  dataLen >= 0)
    {
        AT_SYSINFO at_sysinfo;
        parse_AT_SYSINFO(buff, &dataLen, &at_sysinfo);
    }
    memset(buff, 0, 8192);
    dataLen = 0;     

    /* Set GPS session type */
    char WPDST[25] = { "AT^WPDST=1\r" };
    SendATCommand(sms_serial_fd, WPDST, strlen(WPDST), CONFIG_COMMAND_TIMEOUT); 

    /* Set GPS session start */
    char WPDGP[25] = { "AT^WPDGP\r" };
    SendATCommand(sms_serial_fd, WPDGP, strlen(WPDGP), CONFIG_COMMAND_TIMEOUT); 
    DONGLE_LOG(LOG_INFO, "END of initserial! \n");
    return true;
}

void term_serial()
{
    sleep(3);
    close(sms_serial_fd);
    sms_serial_fd = -1;
}

bool recv_sms(int32_t index)
{
    bool bret = true;
    int32_t  rsp_len = 0;
    char rsp_buf[AT_RSP_MAXLEN] = {0};
    char at_cmd[AT_CMD_MAXLEN] = {0};
    int32_t dataLen = 0;
    const char *FlagList[2] = { CRLF_OK_CRLF, CRLF_CMS_ERR_CRLF };
    if( index < 0 && index > 100 )
    {
        DONGLE_LOG(LOG_ERR,  "%s, wrong sms index parameter, %d \n", __func__, index);

        return false;
    }

    sprintf(at_cmd, "AT^HCMGR=%d\r", index);
    rsp_len = SendATCommandX(sms_serial_fd, at_cmd, strlen(at_cmd), rsp_buf, AT_RSP_MAXLEN, FlagList,
	                         2,  &dataLen, CONFIG_COMMAND_TIMEOUT);
    if( rsp_len == 0 && dataLen >=0 )
    {
        parse_at_rsp(rsp_buf, dataLen);
    }

    if(sms_accept_flag)
    {
        /* delete after remote receiver confirm received */
        rsp_len = AT_RSP_MAXLEN;
        sprintf(at_cmd, "AT+CMGD=%d\r", index);

        if( SendATCommand(sms_serial_fd, at_cmd, strlen(at_cmd), CONFIG_COMMAND_TIMEOUT) != 0)
        {
            DONGLE_LOG(LOG_ERR, "%s, can't remove sms index=%d\n", __func__, index);

            bret = false;
        }
        else
        {
            DONGLE_LOG(LOG_DEBUG,  "sms index=%d removed \n", index);
        }
    }

    return bret;
}

bool pase_AT_HCMGSS(const void *buf, int32_t *len, void *result)
{
    int32_t len_parsed = 0;
    int32_t pos = 0;
    bool ret = true;
    byte *ptr = (byte *)buf;
    /* skip ^HCMGSS:*/
    len_parsed += 8;
    ptr += 8;
    if(find_str(ptr, *len - len_parsed, at_cr_lf, 2, &pos))
    {
        len_parsed += pos + 2;
        ptr += pos + 2;
        ptr[pos] = '\n';
        ptr[pos+1] = '\0';
        DONGLE_LOG(LOG_INFO,"%s", (char *)buf);
        *len = len_parsed;
        sms_send_flag = 0;
    }
    else
    {
        ret = false;
        sms_send_flag = -1;
        DONGLE_LOG(LOG_WARNING, "parsing ^HCMGSS error!\n");
    }
    return ret;
}


bool parse_AT_SMMEMFULL(const void *buf, int32_t *len, void *result)
{
  
    bool ret = true;
    char CMGD[15] = { "AT+CMGD=1,4\r" };
    SendATCommand(sms_serial_fd, CMGD, strlen(CMGD), 10 * CONFIG_COMMAND_TIMEOUT);   
 
    sleep(2);
    return ret;
}

bool parse_AT_HCMGSF(const void *buf, int32_t *len, void *result)
{
    bool ret = true;
    int32_t len_parsed = 0;
    int32_t pos = 0;
    byte *ptr = (byte *)buf;
    /* skip ^HCMGSS: */
    len_parsed += 8;
    ptr += 8;
    if(find_str(ptr, *len - len_parsed, at_cr_lf, 2, &pos))
    {
        ptr[pos] = '\n';
        ptr[pos+1] = '\0';
        DONGLE_LOG(LOG_INFO,"%s", (char *)buf);

        sms_send_flag = -1;
        *len = len_parsed + pos + 2;
    }
    else
    {
        DONGLE_LOG(LOG_ERR, "parsing ^HCMGSF error!");
        ret = false;
    }
    return ret;
}

bool parse_AT_HCMGL(const void *buf, int32_t *len, void *result)
{
    int32_t len_parsed = 0;
    bool check_next_entry = false;
    byte *ptr = (byte *)buf;
 
#if (SMS_PRINTF == 1)    
   debug_dump_buffer(*len, buf);
#endif   

    /* for ^HCMGL:0,1<CR><LF>, at least 12 bytes  */
    while( *len - len_parsed >= 12 )
    {
        int32_t index = 0, tag = 0, pos = 0;
        byte at_hcmgl[] = {0x0D,0x0A,0x5E,0x48,0x43,0x4D,0x47,0x4C};

        if( check_next_entry )
        {
            if( (DONGLE_ZTE_MC2716 == dongle_model) || (DONGLE_HW_MC509 == dongle_model) )
            {
                if( byte_cmp(ptr, at_ok_rsp, 6) )
                {
                    ptr += 6;   /* skip ok */
                    len_parsed += 6;
                    return true; /* OK found, no more entry */
                }
            }
            /* skip previous entry's <CR><LF> */
            ptr += 2;
            len_parsed += 2;

            /* test <CR><LF>^HCMGL */
            if( !byte_cmp(ptr, at_hcmgl, sizeof(at_hcmgl)) )
                break;

            /* skip <CR><LF> */
            ptr += 2;
            len_parsed += 2;
        }
        else
        {
            check_next_entry = true;
        }

        /* skip ^HCMGL: */
        ptr += 7;
        len_parsed += 7;

        /* find option end */
        if( !find_str(ptr, *len - len_parsed, at_cr_lf, 2, &pos) )
        {
            DONGLE_LOG(LOG_ERR, "%s, wrong AT HCMGL response, no CR-LF found\n", __func__);

            return false;
        }

        char option[AT_RSP_MAXLEN] = {0};

        memcpy(option, ptr, pos);
        ptr += pos;
        len_parsed += pos;

        sscanf(option, "%d,%d", &index, &tag);
        DONGLE_LOG(LOG_INFO,  "HCMGL: index=%d, tag=%d \n", index, tag);

        recv_sms(index);
    }

    /* for HW EM660, no OK included */
    if( DONGLE_ZTE_MC2716 == dongle_model )
    {
        if( byte_cmp(ptr, at_ok_rsp, 6) )
        {
            ptr += 6;   /* skip ok */
            len_parsed += 6;
        }
        else
        {
            DONGLE_LOG(LOG_ERR, "%s, wrong AT SMS response, no OK found \n", __func__);

            return false;
        }
    }

    if(DONGLE_HW_MC509 == dongle_model)
    {
        ptr += 2;   /* skip <CR><LF> */
        len_parsed += 2;
        if( byte_cmp(ptr, at_ok_rsp, 6) )
        {
            ptr += 6;   /* skip ok */
            len_parsed += 6;
        }
        else
        {
            DONGLE_LOG(LOG_ERR, "%s, wrong AT SMS response, no OK found \n", __func__);

            return false;
        }
    
    }

    *len = len_parsed;
    return true;
}

bool parse_AT_HCMGR(const void *buf, int32_t *len, void *result)
{
    int32_t pos = 0, len_parsed = 0;
    byte *ptr = (byte *)buf;
    AT_RSP_HCMGR at_hcmgr; 

#if (SMS_PRINTF == 1)    
   debug_dump_buffer(*len, buf);
#endif   

    /* skip ^HCMGR: */
    ptr += 7;
    len_parsed += 7;

    /* find option */
    if( !find_str(ptr, *len - len_parsed, at_cr_lf, 2, &pos) )
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT HCMGR response, no CR-LF found\n", __func__);

        return false;
    }

    char option[AT_RSP_MAXLEN] = {0};
    memcpy(option, ptr, pos);
    ptr += pos;
    len_parsed += pos;

    DONGLE_LOG(LOG_INFO,  "HCMGR option: %s \n", option);
    sscanf(option, "%[^,],%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", 
        at_hcmgr.callerID, &at_hcmgr.year, &at_hcmgr.month, &at_hcmgr.day,
        &at_hcmgr.hour, &at_hcmgr.minute, &at_hcmgr.second, &at_hcmgr.lang,
        &at_hcmgr.format, &at_hcmgr.length, &at_hcmgr.prt, &at_hcmgr.prv, 
        &at_hcmgr.type, &at_hcmgr.stat);

        DONGLE_LOG(LOG_INFO, "%d:%d:%d %d:%d:%d recv %s's SMS len=%d lang=%d format=%d prt=%d\n",
        at_hcmgr.year, at_hcmgr.month, at_hcmgr.day, at_hcmgr.hour, 
        at_hcmgr.minute, at_hcmgr.second, at_hcmgr.callerID, at_hcmgr.length,
        at_hcmgr.lang, at_hcmgr.format, at_hcmgr.prt);


    /* skip <CR><LR> */
    ptr += 2;
    len_parsed += 2;

    /* find sms text */
    if( 6 == at_hcmgr.format )
    {   /* unicode */
        if( !find_str(ptr, *len - len_parsed, at_ctrlz_u, 2, &pos) )
        {
            DONGLE_LOG(LOG_ERR,  "%s, wrong AT HCMGR response\n", __func__);

            return false;
        }
        if( pos != at_hcmgr.length )
        {
            DONGLE_LOG(LOG_WARNING, "%s, wrong SMS length, %d (expected %d)\n", __func__, pos, at_hcmgr.length);
        }
        memcpy(at_hcmgr.msg, ptr, pos);
        at_hcmgr.msg[pos] = '\0';

        debug_dump_unicode(pos, at_hcmgr.msg);

        ptr += pos + 2;   /* msg + ctrl-z */
        len_parsed += pos + 2;
    }
    else if ( 1 == at_hcmgr.format )
    {   /* ascii */
        if( !find_str(ptr, *len - len_parsed, at_ctrlz_a, 1, &pos) )
        {
            DONGLE_LOG(LOG_ERR, "%s, wrong AT HCMGR response\n", __func__);

            return false;
        }
        if( pos != at_hcmgr.length )
        {
            DONGLE_LOG(LOG_WARNING, "%s, wrong SMS length, %d (expected %d)\n", __func__, pos, at_hcmgr.length);
        }
        memcpy(at_hcmgr.msg, ptr, pos);
        at_hcmgr.msg[pos] = '\0';

#if (SMS_PRINTF == 1)
        debug_dump_buffer(pos, at_hcmgr.msg);
#endif     

        ptr += pos + 1;   /* msg + ctrl-z */
        len_parsed += pos + 1;
    }

    if(strncmp(at_hcmgr.msg, send_successed, sizeof(send_successed)))
    {
        SMS_MSG smsMsg;
        memset(&smsMsg, 0, sizeof(smsMsg));
        smsMsg.header.msgId = 1;
        smsMsg.format = at_hcmgr.format;
        strcpy(smsMsg.callerId, at_hcmgr.callerID);
        smsMsg.smsLength = at_hcmgr.length;
        memcpy(smsMsg.text, at_hcmgr.msg, at_hcmgr.length);
        addMsgToFifoMsgQueue(&sms2MgrMsgQueue, (void**)&smsMsg, sizeof(SMS_MSG));
    }
    else/*report "发送成功" */
    {
        char MsgUtf8[32];
        memset(MsgUtf8, 0, sizeof(MsgUtf8));
        switch(at_hcmgr.format)
        {
            case 1:/*ascii*/
                DONGLE_LOG(LOG_INFO,"%s\n", at_hcmgr.msg);
                break;
            case 6:/*unicode-16*/
                if(Utf16ToUtf8(at_hcmgr.msg, at_hcmgr.length, MsgUtf8, 32) == 0)
                {
                    DONGLE_LOG(LOG_INFO,"%s\n", MsgUtf8);
                }
                break;
            default:
                break;
        }

        sms_accept_flag = 1;
    }


    if( (DONGLE_HW_EM660 == dongle_model) || (DONGLE_HW_MC509 == dongle_model))
    {
        if( byte_cmp(ptr, at_cr_lf, 2) )
        {
            ptr += 2;   /* skip <CR><LR> */
            len_parsed += 2;
        }
        else
        {
            DONGLE_LOG(LOG_ERR, "%s, wrong AT response, no CR-LF found \n", __func__);
            return false;
        }
    }

    if( byte_cmp(ptr, at_ok_rsp, 6) )
    {
        ptr += 6;   /* skip OK */
        len_parsed += 6;
    }
    else
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT SMS response, no OK found \n", __func__);
        return false;
    }

    *len = len_parsed;
    return true;
}


bool parse_AT_CMIT_CDSI(const void *buf, int32_t *len, void *result)
{
    int32_t pos = 0, len_parsed = 0;
    byte *ptr = (byte *)buf;
    char option[AT_RSP_MAXLEN] = {0};

    /* skip ^CMTI: +CDSI */
    ptr += 6;
    len_parsed += 6;

    /* find option end */
    if( !find_str(ptr, *len - len_parsed, at_cr_lf, 2, &pos) )
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT CMIT response, no CR-LF found\n", __func__);
        return false;
    }

    /* pos = option_end + 1 */
    memcpy(option, ptr, pos);
    ptr += pos;
    len_parsed += pos;

#if (SMS_PRINTF == 1)    
    debug_dump_buffer(pos, option);
#endif
    sscanf(option, "%[^,],%d", at_cmti.mem, &at_cmti.index); 
    DONGLE_LOG(LOG_INFO,  "CMTI: mem=%s, index=%d\n", at_cmti.mem, at_cmti.index);

    sms_recv_num += 1;

    /* skip <CR><LR> */
    ptr += 2;
    len_parsed += 2;

    return true;
}


bool parse_AT_DSDORMANT(const void *buf, int32_t *len, void *result)
{
    int32_t len_parsed = 0;
    byte *ptr = (byte *)buf;

    /* skip ^DSDORMANT: */
    ptr += 11;
    len_parsed += 11;


    ptr += 1;
    len_parsed += 1;
#if 0
    MOD_log(MODULE_SMS, LOG_DEBUG, "DSDORMANT:%c\n", enabled);
#ifdef SMS_PRINTF
    printf("DSDORMANT:%c\n", enabled);
#endif
#endif

    if( DONGLE_HW_EM660 == dongle_model )
    {
        if( (*len - len_parsed >= 2) && byte_cmp(ptr, at_cr_lf, 2) )
        {
            ptr += 2;   /* skip <CR><LR> */
            len_parsed += 2;
        }
    }

    if( (*len - len_parsed >= 2) && byte_cmp(ptr, at_cr_lf, 2) )
    {
        ptr += 4;   /* skip <CR><LR><CR><LR> */
        len_parsed += 4;
    }

    *len = len_parsed;
    return true;
}

bool parse_AT_HRSSILVL(const void *buf, int32_t *len, void *result)
{
    int32_t pos = 0, len_parsed = 0;
    byte *ptr = (byte *)buf;
    int32_t rssi = 0;
    static int32_t rssi_last = 0;
    DONGLE_LOG(LOG_DEBUG, "buf %s \n", buf);
    sscanf((char*)ptr, "%*[^:]:%d", &rssi);

    /* find option end */
    if( !find_str(ptr, *len - len_parsed, at_cr_lf, 2, &pos) )
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT HRSSILVL response, no CR-LF found\n", __func__);
        return false;
    }

    /* skip ^DSDORMANT:rssi<CR><LF> */
    ptr += pos + 2;
    len_parsed += pos + 2;

    if(abs(rssi_last-rssi)>5)
    {
        rssi_last = rssi;
        DONGLE_LOG(LOG_DEBUG, "RSSILVL:%d\n", rssi);
    }

    *len = len_parsed;
    return true;
}

bool parse_AT_HDRRSSI(const void *buf, int32_t *len, void *result)
{
    bool ret = true;
    int32_t hdrrssi = 0;
    static int32_t hdrrssi_last = 0;
    int32_t len_parsed = 0;
    char *ptr = (char *)buf;
    char *tmp;
    DONGLE_LOG(LOG_DEBUG, "buf %s \n", buf);
    sscanf(ptr, "%*[^:]:%d", &hdrrssi);

    tmp = strstr(ptr, "\r\n");/* <CR><LF> */
    if(tmp)
    {
        len_parsed = strlen("\r\n");
        tmp[len_parsed - 1] = 0;
        if(abs(hdrrssi_last-hdrrssi)>5)
        {
            hdrrssi_last = hdrrssi;
            DONGLE_LOG(LOG_DEBUG, "%s\n", ptr);

        }
        len_parsed = (unsigned int)tmp - (unsigned int)ptr + len_parsed;
    }
    else
    {
        DONGLE_LOG(LOG_DEBUG, "Parsing HDRRSSI/CRSSI error!\n");
        ret = false;
    }
    *len = len_parsed;
    return ret;
}

bool parse_AT_CGMI(const void *buf, int32_t *len, void *result)
{
    int32_t pos = 0, len_parsed = 0;
    byte *ptr = (byte *)buf;
    char option[AT_RSP_MAXLEN] = {0};
    DONGLE_LOG(LOG_DEBUG, "buf %s \n", buf);
    /* skip <CR><LF> */
    ptr += 2;
    len_parsed += 2;

    /* find option end */
    if( !find_str(ptr, *len - len_parsed, at_cr_lf, 2, &pos) )
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT CGMI response, no CR-LF found\n", __func__);

        return false;
    }

    /* pos = option_end + 1 */
    memcpy(option, ptr, pos);
    option[pos] = '\0';

    ptr += pos;
    len_parsed += pos;

    strcpy(dongle_manufacturer, option);
    DONGLE_LOG(LOG_INFO, "Manufacturer: %s\n", dongle_manufacturer);


    /* skip <CR><LR> */
    ptr += 2;
    len_parsed += 2;

    /* check OK rsp */
    if( (*len - len_parsed >= 6) && byte_cmp(ptr, at_ok_rsp, 6) )
    {
        ptr += 6;   /* skip OK */
        len_parsed += 6;
    }
    else
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT CGMI response, no OK found \n", __func__);

        return false;
    }

    *len = len_parsed;
    return true;
}

bool parse_AT_CGMM(const void *buf, int32_t *len, void *result)
{
    int32_t pos = 0, len_parsed = 0; 
    byte *ptr = (byte *)buf;
    char option[AT_RSP_MAXLEN] = {0};
    DONGLE_LOG(LOG_DEBUG, "buf %s \n", buf);
    /* skip <CR><LF> */
    ptr += 2;
    len_parsed += 2;

    /* find option end */
    if( !find_str(ptr, *len - len_parsed, at_cr_lf, 2, &pos) )
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT CGMM response, no CR-LF found\n", __func__);
        return false;
    }

    if( pos >= AT_RSP_MAXLEN )
    {
        DONGLE_LOG(LOG_WARNING, "AT CGMM response is too long, %d \n", pos);
        return false;
    }

    /* pos = option_end + 1 */
    memcpy(option, ptr, pos);
    option[pos] = '\0';

    ptr += pos;
    len_parsed += pos;

    strcpy(dongle_model_string, option);
    DONGLE_LOG(LOG_INFO, "Model: %s\n", dongle_model_string);


    /* skip <CR><LR> */
    ptr += 2;
    len_parsed += 2;

    /* check OK rsp */
    if( (*len - len_parsed >= 6) && byte_cmp(ptr, at_ok_rsp, 6) )
    {
        ptr += 6;   /* skip OK */
        len_parsed += 6;
    }
    else
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT CGMM response, no OK found \n", __func__);

        return false;
    }

    *len = len_parsed;
    return true;
}

bool parse_AT_CGMR(const void *buf, int32_t *len, void *result)
{
    int32_t pos = 0, len_parsed = 0;
    byte *ptr = (byte *)buf;
    char option[AT_RSP_MAXLEN] = {0};
    DONGLE_LOG(LOG_DEBUG, "buf %s \n", buf);
    /* skip <CR><LF> */
    ptr += 2;
    len_parsed += 2;

    /* skip +CGMR: */
    ptr += 6;
    len_parsed += 6;

    /* find option end */
    if( !find_str(ptr, *len - len_parsed, at_cr_lf, 2, &pos) )
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT CGMR response, no CR-LF found\n", __func__);
        return false;
    }

    /* pos = option_end + 1 */
    memcpy(option, ptr, pos);
    option[pos] = '\0';

    ptr += pos;
    len_parsed += pos;

    strcpy(dongle_sw_version, option);
    DONGLE_LOG(LOG_INFO, "SW version: %s\n", dongle_sw_version);

    /* skip <CR><LR> */
    ptr += 2;
    len_parsed += 2;

    /* check OK rsp */
    if( (*len - len_parsed >= 6) && byte_cmp(ptr, at_ok_rsp, 6) )
    {
        ptr += 6;   /* skip OK */
        len_parsed += 6;
    }
    else
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT CGMR response, no OK found \n", __func__);
        return false;
    }

    *len = len_parsed;
    return true;
}

bool parse_AT_CIMI(const void *buf, int32_t *len, void *result)
{
    int32_t pos = 0, len_parsed = 0;
    byte *ptr = (byte *)buf;
    char option[AT_RSP_MAXLEN] = {0};
    DONGLE_LOG(LOG_DEBUG, "buf %s \n", buf);
    /* skip <CR><LF> */
    ptr += 2;
    len_parsed += 2;

    /* find option end */
    if( !find_str(ptr, *len - len_parsed, at_cr_lf, 2, &pos) )
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT CIMI response, no CR-LF found\n", __func__);
        return false;
    }

    /* pos = option_end + 1 */
    memcpy(option, ptr, pos);
    option[pos] = '\0';

    ptr += pos;
    len_parsed += pos;

    strcpy(dongle_uim_imsi, option);
    DONGLE_LOG(LOG_INFO, "SIM/UIM imsi: %s\n", dongle_uim_imsi);


    /* skip <CR><LR> */
    ptr += 2;
    len_parsed += 2;

    /* check OK rsp */
    if( (*len - len_parsed >= 6) && byte_cmp(ptr, at_ok_rsp, 6) )
    {
        ptr += 6;   /* skip OK */
        len_parsed += 6;
    }
    else
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT CIMI response, no OK found \n", __func__);

        return false;
    }

    *len = len_parsed;
    return true;
}

bool parse_AT_HWVER(const void *buf, int32_t *len, void *result)
{
    int32_t pos = 0, len_parsed = 0;
    byte *ptr = (byte *)buf;
    char option[AT_RSP_MAXLEN] = {0};
    DONGLE_LOG(LOG_DEBUG, "buf %s \n", buf);
    /* skip <CR><LF> */
    ptr += 2;
    len_parsed += 2;

    /* skip ^HWVER: */
    ptr += 7;
    len_parsed += 7;

    /* find option end */
    if( !find_str(ptr, *len - len_parsed, at_cr_lf, 2, &pos) )
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT HWVER response, no CR-LF found\n", __func__);
        return false;
    }

    /* pos = option_end + 1 */
    memcpy(option, ptr, pos);
    option[pos] = '\0';

    ptr += pos;
    len_parsed += pos;

    strcpy(dongle_hw_version, option);
    DONGLE_LOG(LOG_INFO, "HW version: %s\n", dongle_hw_version);


    /* skip <CR><LR> */
    ptr += 2;
    len_parsed += 2;

    /* check OK rsp */
    if( (*len - len_parsed >= 6) && byte_cmp(ptr, at_ok_rsp, 6) )
    {
        ptr += 6;   /* skip OK */
        len_parsed += 6;
    }
    else
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT HWVER response, no OK found \n", __func__);

        return false;
    }

    *len = len_parsed;
    return true;
}

bool parse_AT_MEID(const void *buf, int32_t *len, void *result)
{
    int32_t pos = 0, len_parsed = 0;
    byte *ptr = (byte *)buf;
    char option[AT_RSP_MAXLEN] = {0};
    DONGLE_LOG(LOG_DEBUG, "buf %s \n", buf);
    /* skip <CR><LF> */
    ptr += 2;
    len_parsed += 2;

    /* find option end */
    if( !find_str(ptr, *len - len_parsed, at_cr_lf, 2, &pos) )
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT MEID response, no CR-LF found\n", __func__);

        return false;
    }

    /* pos = option_end + 1 */
    memcpy(option, ptr, pos);
    option[pos] = '\0';

    ptr += pos;
    len_parsed += pos;

    strcpy(dongle_meid, option);
    DONGLE_LOG(LOG_INFO, "MEID: %s\n", dongle_meid);


    /* skip <CR><LR> */
    ptr += 2;
    len_parsed += 2;

    /* check OK rsp */
    if( (*len - len_parsed >= 6) && byte_cmp(ptr, at_ok_rsp, 6) )
    {
        ptr += 6;   /* skip OK */
        len_parsed += 6;
    }
    else
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT MEID response, no OK found \n", __func__);

        return false;
    }

    *len = len_parsed;
    return true;
}

bool parse_AT_SYSINFO(const void *buf, int32_t *len, void *result)
{
    int32_t pos = 0, len_parsed = 0;
    byte *ptr = (byte *)buf;
    char option[AT_RSP_MAXLEN] = {0};
    AT_SYSINFO *at_sysinfo = (AT_SYSINFO *)result;
     DONGLE_LOG(LOG_DEBUG, "buf %s \n", buf);    
    /* skip <CR><LF> */
    ptr += 2;
    len_parsed += 2;

    /* skip ^SYSINFO: */
    ptr += 9;
    len_parsed += 9;

    /* find option end */
    if( !find_str(ptr, *len - len_parsed, at_cr_lf, 2, &pos) )
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT CMIT response, no CR-LF found\n", __func__);

        return false;
    }

    /* pos = option_end + 1 */
    memcpy(option, ptr, pos);
    ptr += pos;
    len_parsed += pos;

    DONGLE_LOG(LOG_DEBUG,"option is %s \n", option);
    sscanf(option, "%d,%d,%d,%d,%d", &at_sysinfo->srv_status, &at_sysinfo->srv_domain,
           &at_sysinfo->roam_status, &at_sysinfo->sys_mode, &at_sysinfo->sim_state);

    const char *sim_state = NULL;
    if( 1 == at_sysinfo->sim_state )
    {
        sim_state = "avaiable";
    }
    else if( 255 == at_sysinfo->sim_state )
    {
        sim_state = "not exist";
    }
    else
    {
        sim_state = "unknown";
    }

    //if status > 4, means wrong decoding happened
    if(at_sysinfo->srv_status > 4 )
    {
        memset(at_sysinfo, 0x0, sizeof(AT_SYSINFO));
        DONGLE_LOG(LOG_WARNING, "SYSINFO: Parsing failure. \n");
    }
    else
    {
        DONGLE_LOG(LOG_INFO, "SYSINFO: SIM card (%s), service status (%s)\n", sim_state, srv_status[at_sysinfo->srv_status]);
    }

    /* skip <CR><LR> */
    ptr += 2;
    len_parsed += 2;

    /* check OK rsp */
    if( (*len - len_parsed >= 6) && byte_cmp(ptr, at_ok_rsp, 6) )
    {
        ptr += 6;   /* skip OK */
        len_parsed += 6;
    }
    else
    {
        DONGLE_LOG(LOG_ERR, "%s, wrong AT SYSINFO response, no OK found \n", __func__);

        return false;
    }

    *len = len_parsed;
    return true;
}

void parse_at_rsp(const void* buf, int32_t len)
{
    int32_t i = 0, j = 0;
    byte *ptr = (byte *)buf;
    int32_t len_remain = len;

    DONGLE_LOG( LOG_DEBUG, "Response: %s \n", buf);

#if (SMS_PRINTF == 1)
    debug_ascii((char *)buf, len);
#endif

    if( len < AT_RSP_MINLEN )
    {
        DONGLE_LOG( LOG_ERR, "%s, wrong AT response, len = %d ", __func__, len);

        return;
    }

    while( len_remain > 0 )
    {
        if( byte_cmp(ptr, at_ok_rsp, 6) )
        {
            DONGLE_LOG(LOG_DEBUG, "OK AT response found \n");

            ptr += 6;
            len_remain -= 6;
        }
        else if( (len_remain >= 14) && byte_cmp(ptr, at_no_carrier, 14) )
        {
            ptr += 14;
            len_remain -= 14;
            DONGLE_LOG(LOG_NOTICE, "no carrier reported \n");

        }
        else if ( byte_cmp(ptr, at_cr_lf, 2) )
        {
            ptr += 2;
            len_remain -= 2;

            for( i = 0; i < (int32_t)(sizeof(at_cmd_list) / sizeof(AT_CMD)); ++i )
            {
                if( byte_cmp(ptr, (byte*)(at_cmd_list[i].cmd), at_cmd_list[i].len) )
                {
                    DONGLE_LOG( LOG_DEBUG,"AT %s response received\n", at_cmd_list[i].cmd);
                    if( NULL != at_cmd_list[i].parser )
                    {
                        int32_t len_parsed = len_remain;
                        void *result = NULL;
                        at_cmd_list[i].parser(ptr, &len_parsed, result);

                        ptr += len_parsed;
                        len_remain -= len_parsed;
                    }
                    else
                    {
                        /* find next <CR><LR> */
                        DONGLE_LOG( LOG_DEBUG,"no parser for it\n");
                        for( j = 0; j < len_remain; ++j )
                        {
                            if( byte_cmp(ptr+j, at_cr_lf, 2) )
                                break;
                        }
#if (SMS_PRINTF == 1)                        
                        /* ignore no-parser response */
                        debug_dump_buffer(j, ptr);
#endif         
                        ptr += j + 2; /* rsp + <CR><LR> */
                        len_remain -= j + 2;
                    }
                    break;
                }
                else
                {
#if (SMS_PRINTF == 1)
                    DONGLE_LOG( LOG_DEBUG,"%s\n", ptr);
#endif /* SMS_PRINTF */
                }
            }
            if( i == sizeof(at_cmd_list) / sizeof(AT_CMD) )
            {
                DONGLE_LOG(LOG_WARNING, "%s, unsupported AT response found \n", __func__);


                /* find next <CR><LR> */
                for( j = 0; j < len_remain; ++j )
                {
                    if( byte_cmp(ptr+j, at_cr_lf, 2) )
                        break;
                }
#if (SMS_PRINTF == 1)
                /* ignore unknown response */
                debug_dump_buffer(j, ptr);
#endif
                ptr += j + 2; /* unknown rsp + <CR><LR> */
                len_remain -= j + 2;
            }
        }
        else if ( byte_cmp(ptr, at_prefix, 2) )
        {
            ptr += 2;
            len_remain -= 2;

            for( i = 0; i < (int32_t)(sizeof(at_cmd_list) / sizeof(AT_CMD)); ++i )
            {
                if( byte_cmp(ptr, (byte*)(at_cmd_list[i].cmd), at_cmd_list[i].len) )
                {
                    DONGLE_LOG(LOG_INFO, "AT %s echo received\n", at_cmd_list[i].cmd);


                    ptr += at_cmd_list[i].len;
                    len_remain -= at_cmd_list[i].len;

                    break;
                }
            }
            if( i == sizeof(at_cmd_list) / sizeof(AT_CMD) )
            {
                DONGLE_LOG(LOG_WARNING, "%s, unknown AT echo found \n", __func__);

            }

            /* find 0x0D */
            for( j = 0; j < len_remain; ++j )
            {
                if( *(ptr + j) == 0x0D )
                    break;
            }
            if( j < len_remain )
            {
                /* skip * + 0x0D */
                ptr += j + 1;
                len_remain -= j + 1;
            }
            else
            {
                DONGLE_LOG(LOG_WARNING, "%s, wrong AT echo, can't find 0x0D \n", __func__);

            }
        }
        else
        {
            if( len_remain > 2 )
            {
#if (SMS_PRINTF == 1)
                DONGLE_LOG(LOG_WARNING, "%s, unknown AT response bit sequence, len = %d \n", __func__, len);
                debug_dump_buffer(len_remain, ptr);
#endif                
                ptr += 1;
                len_remain -= 1;
            }
            else
            {
                len_remain -= 1;
            }
        }
    }
}

void sms_task_hdlr()
{
    int32_t  rsp_len = 0, nret = 0;
    char rsp_buf[AT_RSP_MAXLEN] = {0};

    MSG_SMS_STATUS send_status = MSG_SMS_IDEL;
    SMS_MSG SmsMsg;
 
    const char *FlagList[1] = { CRLF_OK_CRLF};
    memset(&SmsMsg, 0, sizeof(SMS_MSG));
    int32_t rspLen = 0;
    int32_t dataLen = 0;
    static char HCMGL[15] = { "AT^HCMGL\r"};

    sms_process = true; 
    while( sms_process )
    {
//for test 
#ifdef MODULE_TEST
        if (testSms)
        {
            DONGLE_LOG(LOG_WARNING, "----- test module smstask ----- %04x\n", CMD_CODE_SYSMONITOR_TEST_MODULE);
            while(1)
            {

            }
        }
#endif

        fd_set fds_cur = fds_collection;
        struct timeval selectTimeout = {SELECT__S, SELECT_US};

        nret = select(max_fd + 1, &fds_cur, NULL, NULL, &selectTimeout);

        if(nret > 0 )
        {
            if( FD_ISSET(sms_serial_fd, &fds_cur) )
            {
                memset(rsp_buf, 0, AT_RSP_MAXLEN);
                rsp_len = read(sms_serial_fd, rsp_buf, AT_RSP_MAXLEN);
                if( rsp_len > 0 )
                {
                    DONGLE_LOG(LOG_DEBUG,"TE popup!\n");
#if (SMS_PRINTF == 1)
                    debug_dump_buffer(rsp_len, rsp_buf);
#endif                    
                    parse_at_rsp(rsp_buf, rsp_len);
                }
            }
        }
        else if ( nret == 0 )
        {
#if (SMS_PRINTF == 1)                
            /* select timeout */
            DONGLE_LOG(LOG_DEBUG, "select timeout \n");
#endif
        }
        else 
        {   // nret < 0, run into error case; errno = 9 is bad file descriptor
            if((nret == -1) && (errno == EINTR))
            {
                ;
            }
            else
			{
                DONGLE_LOG(LOG_NOTICE, "%s: select errno=[%d:%s] \n", errno, strerror(errno));
                reset_dongle(dongle_at_port);
            }
        }

        /* read sms from MEM */
        if( sms_recv_num > 0 || sms_list)
        {
           // sms_list = 0;
            sms_list = 0;
            rsp_len = AT_RSP_MAXLEN;
            rspLen = SendATCommandX(sms_serial_fd, HCMGL, strlen(HCMGL), rsp_buf, AT_RSP_MAXLEN, FlagList,
	                                1,  &dataLen, CONFIG_COMMAND_TIMEOUT * 10);
           if ( rspLen == 0 &&  dataLen >= 0)
           {
               parse_at_rsp(rsp_buf, dataLen);
               sms_recv_num = 0;
           }
        }

        /* check sms send queue */
        if(send_status == MSG_SMS_IDEL)
        {
            int32_t sms_count = getQueuedMsgsCount(&mgr2SmsMsgQueue.pool);
            if( sms_count > 0 )
            {
                void *buffer = NULL;
                uint32_t length = 0;
                /* get one from queue */
                getMsgFromFifoMsgQueue(&mgr2SmsMsgQueue, &buffer, &length);
                if( length != 0 )
                {
                    MSG_HEADER *header = (MSG_HEADER *)buffer;
                    switch( header->msgId )
                    {
                        case MSG_ID_SMS:
                        {
                            SMS_MSG *smsMsg = (SMS_MSG *)buffer;
                            memcpy(&SmsMsg, smsMsg, sizeof(SMS_MSG));
                            if( smsMsg->header.msgId == 1 )
                            {
                                DONGLE_LOG(LOG_DEBUG, "Going to send a sms to %s, format=%d, length=%d\n",
                                           smsMsg->callerId, smsMsg->format, smsMsg->smsLength);

                                bool unicode = false;
                                if( PARA_VALUE_3G_SMS_FORMAT_UNICODE == smsMsg->format )
                                {
                                    unicode = true;
                                }

                                nret = send_sms(smsMsg->callerId, (void*)smsMsg->text, smsMsg->smsLength, unicode);
                                send_status = MSG_SMS_SENDING;
                                sms_resend_count = 0;
                                sms_accept_flag = 0;
                                gettimeofday(&sms_timer, NULL);

                                if(nret > 0)
                                {
                                    /* send fail one time */
                                    sms_send_flag = -1;
                                }
                                else if(nret < 0)
                                {
                                    /* modem reseting */
                                    send_status = MSG_SMS_IDEL;
                                }
                                else
                                {
                                    /* send successed */
                                    sms_send_flag = 0;
                                }
                            }
							
                            break;							
                        }
                        case MSG_ID_GET_SIM_STATE:
                        {
                            char rsp_buf[AT_RSP_MAXLEN] = {0};
                            int32_t rspLen = 0;
                            char SYSINFO[15] = { "AT^SYSINFO\r" } ;
                            int32_t dataLen = 0;
                            rspLen = SendATCommandX(sms_serial_fd, SYSINFO, strlen(SYSINFO), rsp_buf, AT_RSP_MAXLEN, 
								                    FlagList, 1,  &dataLen, CONFIG_COMMAND_TIMEOUT);
                            AT_SYSINFO at_sysinfo;
                            if ( rspLen == 0 &&  dataLen >= 0)
                            {                                   
                                parse_AT_SYSINFO(rsp_buf, &dataLen, &at_sysinfo);
                            }

                            SIM_STATE simst;
                            simst.header.msgId = MSG_ID_SIM_STATE_RSP;
                            simst.valid = at_sysinfo.sim_state;
                            addMsgToFifoMsgQueue(&sms2MgrMsgQueue, (void**)&simst, sizeof(SIM_STATE));
                            send_status = MSG_SMS_IDEL;
							
                            break;
                        }
                        case MSG_ID_RESET:
                        {
                            DONGLE_LOG(LOG_NOTICE, "reseting 3g dongle \n");
                               
                            reset_dongle(dongle_at_port);
                            sms_list = 1;
							
                            break;							
                        }
                        default:
                            break;
                    }
                }
            }
        }
        else if(send_status == MSG_SMS_SENDING)
        {
            if(!sms_send_flag)/*send success*/
            {
                send_status = MSG_SMS_WAIT_CONFIRM;
                DONGLE_LOG(LOG_INFO, "confirming sent....\n");
            }
            else if(sms_send_flag < 0)/*send fail, resend this msg*/
            {
                if(sms_resend_count++ < SMS_RESEND_MAX_COUNT)
                {
                    int32_t retval;
                    SMS_MSG *smsMsg = &SmsMsg;
                    DONGLE_LOG(LOG_INFO, "Resend this Msg....\n");
                    retval = send_sms(smsMsg->callerId, (void*)smsMsg->text, smsMsg->smsLength, (smsMsg->format == PARA_VALUE_3G_SMS_FORMAT_UNICODE) ? 1 : 0);
                    if(!retval)
                    {
                        send_status = MSG_SMS_SENDING;
                        sms_send_flag = 0;
                        sms_accept_flag = 0;
                        gettimeofday(&sms_timer, NULL);
                    }
                }
                else
                {
                    /* drop this message*/
                    DONGLE_LOG(LOG_INFO, "send Msg timeout! drop this message!\n");
                    send_status = MSG_SMS_IDEL;
                    sms_resend_count = 0;
                }
            }
            else
            {
                /* wait respone */
                struct timeval cur;
                gettimeofday(&cur, NULL);
                if(cur.tv_sec - sms_timer.tv_sec > MSG_CONFIRM_TIMEOUT)/*timeout*/
                {
                    DONGLE_LOG(LOG_WARNING, "send Msg fail! drop this message!\n");
                    send_status = MSG_SMS_IDEL;
                    sms_resend_count = 0;
                }
            }
        }
        else if(send_status == MSG_SMS_WAIT_CONFIRM)
        {
            struct timeval cur;
            gettimeofday(&cur, NULL);
            if(cur.tv_sec - sms_timer.tv_sec > MSG_CONFIRM_TIMEOUT)/*timeout*/
            {
                DONGLE_LOG(LOG_WARNING,"%s:can not receive in time!", SmsMsg.callerId);
                
                send_status = MSG_SMS_IDEL;
            }
            else
            {
                if(sms_accept_flag)
                {
                    send_status = MSG_SMS_ACCEPTED;
                }
            }
        }
        else if(send_status == MSG_SMS_ACCEPTED)
        {
            DONGLE_LOG(LOG_WARNING, "receiver accepted!\n");
            sms_resend_count = 0;
            send_status = MSG_SMS_IDEL;
        }
        else
        {
            ;/*do nothing, idle*/
        }

        setTickTrue();
        /* check 3g-wan & dongle alive every 30 seconds  */
        {
            static int32_t alive_counter = 0;
            static int32_t fail_counter = 0;
   
            const char *cmd_3g_status = "ifstatus wan";
            char buf_tmp[64] = {0};
            char *str_tmp;
            FILE *ftmp;

            if(alive_counter++>200)
            {
                /* check 3g-wan status and AT interface alive */
                /* in case AT interface no response, reset the dongle */
                /* in case 3g-wan down, force it up */

                alive_counter = 0;
                if( SendATCommand(sms_serial_fd, AT, strlen(AT), CONFIG_COMMAND_TIMEOUT) != 0)
                {
                    /* no OK response, reset the dongle*/
                    DONGLE_LOG(LOG_INFO,"\nAT interface no respondse!\n");

                    if(fail_counter++ > 3)
                    {
                        fail_counter = 0;

                        reset_dongle(dongle_at_port);
                        continue; /* next round to check 3g wan */
                    }
                }
                else
                {
                    /* AT interface is ok*/
                    fail_counter = 0;
                }
				
                ftmp = popen(cmd_3g_status, "r");
                if(ftmp)
                {
                    memset(buf_tmp, 0, 64);
                    if(fread(buf_tmp, 1, 63, ftmp) > 0)
                    {
                        str_tmp = strstr(buf_tmp, "\"up\":");
                        if(str_tmp)
                        {
                            if(strncmp(str_tmp+6, "true", 4))/* 3g wan is down */
                            {
                         
                                DONGLE_LOG(LOG_WARNING,"3G wan is down, force up\n");
                                system("ifup wan"); /* up 3g wan */
                                continue;
                            }
                        }
                    }
					
                    pclose(ftmp);
                }
                else
                {
                    DONGLE_LOG(LOG_WARNING,"can not get status!\n");
                }
            }
            else
            {
                /* TODO nothing */
            }
        }
    }
}


static void* sms_task_thread(void *arg __attribute__((unused)))
{
    DONGLE_LOG(LOG_WARNING, "smsTask thread id is %lu \n", pthread_self());
    pthread_setname_np(pthread_self(), "smsTask");

    dongle_model = DONGLE_HW_MC509;
    sms_list = 1;

    while(init_serial(dongle_at_port) == false)
    {
        DONGLE_LOG(LOG_NOTICE, "Open 3g AT interface failed!\n");
        raise_alarm(CMD_EVT_ALARM_SMS_TASK_DOWN, PARA_TYPE_3G_ALARM_REASON_PORT_ERR);
        sleep(60);
    }

    smsIsOk = true;

    sms_task_hdlr();

    term_serial();
    smsIsOk = false;
    DONGLE_LOG(LOG_WARNING, "Exiting the smsTask thread\n");
    raise_alarm(CMD_EVT_ALARM_SMS_TASK_DOWN, PARA_TYPE_3G_ALARM_REASON_STOP);
    
    pthread_exit((void*)0);
}

bool getpingRsp(char *cmd)
{
    FILE *fpipe = (FILE *)popen(cmd, "r");
    if ( fpipe == NULL )
    {
        return false;
    }

    char pingData[1024] = {0};
    char data[128] = {0};
    int32_t len = 0;

    while( NULL != fgets(data, 128, fpipe) )
    {
        len += strlen(data);
        if ( len >= 1024 )
        {
           break;
        }
        strcat(pingData, data);
        memset(data, 0, 128);
    }

    DONGLE_LOG(LOG_INFO, "ping data is %s\n", pingData);
    pclose(fpipe);
    if ( strstr(pingData, "time=") )
    {
        return true;
    }

    return false;

}

static void* checkWan_thread(void *arg __attribute__((unused)))
{
    pthread_setname_np(pthread_self(), "checkWan");
    int32_t failPing = 0 ;
    char buf_tmp[128] = {0};
    int32_t count = 0;
    int32_t i = 0;

    while(1)
    {
        if(count > WAN_CHECK_INTERVAL)
        {
        	for(i = 0; i < TEST_PUBLIC_IP_NUM; i++)
        	{
                memset(buf_tmp, 0, 128);
                sprintf(buf_tmp, "ping -c 3 %s", ipaddr[i]);
                if (getpingRsp(buf_tmp))
                {
                    break;
                }
        	}

			if(i >=  TEST_PUBLIC_IP_NUM)
			{
			    failPing++;
			}
			else
			{
			    //IP is ok, clear the fail ping couter
			    failPing = 0;
			}
			
            if (failPing >= MAX_FAILED_PING)
            {
                failPing = 0;
                DONGLE_LOG(LOG_WARNING,"3g wan is down, force up\n");
                system("ifup wan"); /* up 3g wan */
            }

			count = 0;
		}

		count++;
		sleep(1);

		SetCheckWanIsOk();		
#ifdef MODULE_TEST
        if (testCheckWan)
        {
             DONGLE_LOG(LOG_WARNING,"----- test module check wan ----- %04x\n", CMD_CODE_SYSMONITOR_TEST_MODULE);
            while(1)
            {

            }
        }
#endif
#if 0
        if ( count++ >= 30)
        {
            if (sms_serial_fd > 0 && checkWanIsTrue())
            {
                for ( ; i < 5; i++)
                {
                    memset(buf_tmp, 0, 128);
                    sprintf(buf_tmp, "ping -c 3 %s", ipaddr[i]);
                    if (getpingRsp(buf_tmp))
                    {
                        break;
                    }
                }

                if ( i >= 5 )
                {
                    fail_p++;
                }
        
                if (fail_p >= 6)
                {
                    fail_p = 0;
                    DONGLE_LOG(LOG_WARNING,"3g wan is down, force up\n");
                    system("ifup wan"); /* up 3g wan */
                }
            
                i = 0;
            }

            count = 0;
       }

  	   sleep(1);
#endif
    }

    pthread_exit((void*)0);
}

bool initckeckWan()
{
    pthread_t check3gwan;
    if(pthread_create(&check3gwan, NULL, checkWan_thread, 0))
    {
        return false;
    }
    
    DONGLE_LOG(LOG_INFO, "checkWan_thread created successfully\n");       
    return true;
}

bool initSmsTask()
{
    pthread_t       thread;
    pthread_attr_t  attr;
    struct sched_param sched;
    int32_t minAllowedPrio, maxAllowedPrio;
    int32_t schedPolicy = SCHED_OTHER;
    int32_t schedPriority = 0;
    signal(SIGCHLD, SIG_IGN);
    DONGLE_LOG(LOG_INFO, "smsTask schedPolicy is: %d \n",schedPolicy );
    DONGLE_LOG(LOG_INFO, "smsTask schedPriority is: %d \n",schedPriority );

    if( pthread_attr_init(&attr) )
    {
        DONGLE_LOG(LOG_ERR, "pthread_attr_init failed : %s\n", strerror(errno));
        return false;
    }

    if( pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) )
    {
        DONGLE_LOG(LOG_ERR, "pthread_attr_setinheritsched failed : %s\n", strerror(errno));
        return false;
    }

    if( pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) )
    {
        DONGLE_LOG(LOG_ERR, "pthread_attr_setdetachstate failed: %s\n", strerror(errno));
        return false;
    }

    /****************** Setup scheduling **************************/
    /* If we are not superuser, don't try changing scheduling */
    if( (getuid() != 0) && (schedPolicy != SCHED_OTHER) )
    {
        DONGLE_LOG( LOG_ERR, "don't have permission for ttisched != OTHER\n");
        return false;
    }

    if( schedPolicy == SCHED_OTHER && schedPriority != 0 )
    {
        DONGLE_LOG( LOG_ERR, "maxp %d invalid for ttisched OTHER (must be 0)\n",schedPriority);
        return false;
    }

    if( (minAllowedPrio = sched_get_priority_min(schedPolicy)) < 0 )
    {
        DONGLE_LOG(LOG_ERR, "sched_get_priority_min failed : %s\n", strerror(errno));
        return false;
    }

    if( (maxAllowedPrio = sched_get_priority_max(schedPolicy)) < 0)
    {
        DONGLE_LOG(LOG_ERR, "sched_get_priority_max failed : %s\n", strerror(errno));
        return false;
    }

    if( schedPriority > maxAllowedPrio )
    {
        DONGLE_LOG(LOG_ERR, "xp %d greater than max allowed for ttisched, %d\n",
                schedPriority, maxAllowedPrio);
        return false;
    }

    if( schedPriority < minAllowedPrio )
    {
        DONGLE_LOG(LOG_ERR, "maxp %d lower than min allowed for ttisched, %d\n",
                schedPriority, minAllowedPrio);
        return false;
    }

    if( pthread_attr_setschedpolicy(&attr,schedPolicy) )
    {
        DONGLE_LOG(LOG_ERR, "pthread_attr_setschedpolicy failed: %s\n", strerror(errno));
        return false;
    }

    // Get the scheduling-parameters portion of the attr structure initialized
    // via pthread_attr_init() above
    if( pthread_attr_getschedparam(&attr, &sched) )
    {
        DONGLE_LOG(LOG_ERR, "pthread_attr_getschedparam failed : %s\n", strerror(errno));
        return false;
    }
    // Update the priority with the value passed in
    sched.sched_priority = schedPriority;
    // Update the priority in the attr structure
    if( pthread_attr_setschedparam(&attr, &sched) )
    {
        DONGLE_LOG(LOG_ERR, "pthread_attr_setschedparam failed : %s\n", strerror(errno));
        return false;
    }

    DONGLE_LOG(LOG_INFO, "smstask thread using policy %d at priority %d\n",
               schedPolicy, schedPriority);

    if( pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) )
    {
        DONGLE_LOG(LOG_ERR, "pthread_attr_setscope failed : %s\n", strerror(errno));
        return false;
    }

    DONGLE_LOG(LOG_INFO, "%s, begin to create smstask thread \n", __func__);
    if( pthread_create(&thread, &attr, sms_task_thread, 0) )
    {
        DONGLE_LOG(LOG_ERR, "pthread_create smstask thread failed: %s\n", strerror(errno));
        return false;
    }
    
    DONGLE_LOG(LOG_INFO, "smstask Thread created successfully\n");

    return true;
}

void stopSmsTask()
{
    sms_process = false;
}

